package platformconn

import (
	"errors"
	"fmt"
	"iot-base/auth/logger"
	"net"
	"sync"
	"time"
)

var (
	m               sync.Mutex
	PlatformConnMap = make(map[int64]PlatformConn)
)

//此模块用于创建所有连接的管理
type PlatformConn struct {
	IP   string
	Send chan []byte
	Rev  chan PlatformRev
	Stop chan struct{}
	Conn *net.TCPConn
}

type PlatformRev struct {
	Rev []byte
	ok  bool
}

func GetPlatformConnById(id int64) *PlatformConn {
	if v, ok := PlatformConnMap[id]; ok {
		return &v
	} else {
		return nil
	}
}

func SetPlatformConnById(id int64, conn PlatformConn) {
	m.Lock()
	PlatformConnMap[id] = conn
	m.Unlock()
}

func DelPlatformConnById(id int64) {
	delete(PlatformConnMap, id)
}

func (t *PlatformConn) Start() {
	if t != nil {
		go t.startPlatform()
	}
}

func (t *PlatformConn) startPlatform() {
	for {
		if t == nil {
			logger.Log.Error("platform conn is nil")
			return
		}
		select {
		case send := <-t.Send:
			if t.Conn == nil {
				IP, err := net.ResolveTCPAddr("tcp", t.IP)
				if err != nil {
					logger.Log.Error("connect tcp is err:" + IP.String())
					return
				}
				conn, err := net.DialTCP("tcp", nil, IP)
				if err != nil {
					logger.Log.Error("connect tcp is err:" + IP.String())
					return
				}
				err = conn.SetKeepAlive(true)
				if err != nil {
					logger.Log.Error("tcp set keepAlive err:" + IP.String())
					return
				}
				err = conn.SetKeepAlivePeriod(time.Second * 20)
				if err != nil {
					logger.Log.Error("tcp set keepAlive period is err:" + IP.String())
					return
				}
				t.Conn = conn
				//conn, err := net.Dial("tcp", t.IP)
				if err != nil {
					t.Conn = nil
					logger.Log.Error("connect is err!", err)
					fmt.Println("connect is err!", err)
					t.Rev <- PlatformRev{
						[]byte(err.Error()),
						false,
					}
					if conn != nil {
						conn.Close()
					}
					continue
				}
			}
			_, err := t.Conn.Write(send)
			if err != nil {
				t.Conn = nil
				logger.Log.Error("conn write err!", err)
				fmt.Println("conn write err!", err)
				t.Rev <- PlatformRev{
					[]byte(err.Error()),
					false,
				}
				continue
			}
			readBuf := make([]byte, 2048)
			n, err := t.Conn.Read(readBuf)
			if err != nil {
				t.Conn = nil
				logger.Log.Error("conn read err!", err)
				fmt.Println("conn read err!", err)
				t.Rev <- PlatformRev{
					[]byte(err.Error()),
					false,
				}
				continue
			}
			t.Rev <- PlatformRev{
				readBuf[:n],
				true,
			}
		case <-t.Stop:
			fmt.Println("stop goroute")
			return
		}
	}
}

func (t *PlatformConn) SendStr(data string, timeout int) ([]byte, error) {
	if t == nil {
		return nil, errors.New("platform is nil")
	}
	return t.SendByte([]byte(data), timeout)
}

func (t *PlatformConn) SendByte(data []byte, timeout int) ([]byte, error) {
	if t == nil {
		return nil, errors.New("platform is nil")
	}
	done := make(chan struct{}, 1)
	var res = PlatformRev{}
	go func() {
		t.Send <- data
		res = <-t.Rev
		done <- struct{}{}
	}()
	select {
	case <-time.After(time.Second * time.Duration(timeout)): //超时
		_, err := fmt.Printf("timeout err")
		return nil, err
	case <-done: //程序正常结束
		if res.ok {
			return res.Rev, nil
		} else {
			return nil, errors.New(string(res.Rev))
		}
	}
}

func (t *PlatformConn) Close() {
	if t == nil {
		return
	}
	t.Stop <- struct{}{}
}
